import asyncio
import random
import time


def normal_fib():
    def old_fib(n):
        res = [0] * n
        index = 0
        a = 0
        b = 1
        while index < n:
            res[index] = b
            a, b = b, a + b
            index += 1
        return res

    print('-' * 10 + 'test old fib' + '-' * 10)
    for fib_res in old_fib(10):
        print(fib_res)


def yield_fib():
    def fib(n):
        index = 0
        a = 0
        b = 1
        while index < n:
            yield b  # 生成器，用到了才生成，节省内存资源
            a, b = b, a + b
            index += 1

    print('-' * 10 + 'test yield fib' + '-' * 10)
    for fib_res in fib(10):
        print(fib_res)


def send_fib():
    def stupid_fib(n):
        index = 0
        a = 0
        b = 1
        while index < n:
            sleep_cnt = yield b  # send可以由外面传递过来值
            print('let me think {0} secs'.format(sleep_cnt))
            time.sleep(sleep_cnt)
            a, b = b, a + b
            index += 1

    print('-' * 10 + 'test yield send' + '-' * 10)
    N = 20
    sfib = stupid_fib(N)
    fib_res = next(sfib)
    while True:
        print(fib_res)
        try:
            fib_res = sfib.send(random.uniform(0, 0.5))
        except StopIteration:
            break


def yield_from():
    def copy_fib(n):
        def fib(n):
            index = 0
            a = 0
            b = 1
            while index < n:
                yield b
                a, b = b, a + b
                index += 1

        print('I am copy from fib')
        yield from fib(n)  # 接函数方法返回的生成器
        print('Copy end')

    print('-' * 10 + 'test yield from' + '-' * 10)
    for fib_res in copy_fib(4):
        print(fib_res)

    def copy_stupid_fib(n):
        def stupid_fib(n):
            index = 0
            a = 0
            b = 1
            while index < n:
                sleep_cnt = yield b
                print('let me think {0} secs'.format(sleep_cnt))
                time.sleep(sleep_cnt)
                a, b = b, a + b
                index += 1

        print('I am copy from stupid fib')
        yield from stupid_fib(n)  # 接函数方法返回的生成器
        print('Copy end')

    print('-' * 10 + 'test yield from and send' + '-' * 10)
    N = 4
    csfib = copy_stupid_fib(N)
    fib_res = next(csfib)
    while True:
        print(fib_res)
        try:
            fib_res = csfib.send(random.uniform(0, 0.5))
        except StopIteration:
            break


def coroutine_module():
    @asyncio.coroutine
    def smart_fib(n):
        index = 0
        a = 0
        b = 1
        while index < n:
            sleep_secs = random.uniform(0, 0.2)
            yield from asyncio.sleep(sleep_secs)
            print('Smart one think {} secs to get {}'.format(sleep_secs, b))
            a, b = b, a + b
            index += 1

    @asyncio.coroutine
    def stupid_fib(n):
        index = 0
        a = 0
        b = 1
        while index < n:
            sleep_secs = random.uniform(0, 0.4)
            yield from asyncio.sleep(sleep_secs)
            print('Stupid one think {} secs to get {}'.format(sleep_secs, b))
            a, b = b, a + b
            index += 1

    loop = asyncio.get_event_loop()
    tasks = [
        (smart_fib(4)),
        # (stupid_fib(4)),
    ]
    loop.run_until_complete(asyncio.wait(tasks))
    print('coroutine_module All fib finished.')
    loop.close()


def py_3_5_async():
    async def smart_fib(n):
        index = 0
        a = 0
        b = 1
        while index < n:
            sleep_secs = random.uniform(0, 0.2)
            await asyncio.sleep(sleep_secs)  # 阻塞等待值的操作需要调用await
            print('Smart one think {} secs to get {}'.format(sleep_secs, b))
            a, b = b, a + b
            index += 1

    async def stupid_fib(n):
        index = 0
        a = 0
        b = 1
        while index < n:
            sleep_secs = random.uniform(0, 0.4)
            await asyncio.sleep(sleep_secs)
            print('Stupid one think {} secs to get {}'.format(sleep_secs, b))
            a, b = b, a + b
            index += 1

    loop = asyncio.get_event_loop()
    tasks = [
        asyncio.ensure_future(smart_fib(10)),
        asyncio.ensure_future(stupid_fib(10)),
    ]
    loop.run_until_complete(asyncio.wait(tasks))
    print('py_3_5_async All fib finished.')
    loop.close()


if __name__ == '__main__':
    # normal_fib()
    # yield_fib()
    # send_fib()
    # yield_from()
    # coroutine_module()
    py_3_5_async()
    '''
    实际公司使用一下的多一点
    https://github.com/twisted/twisted
    https://github.com/gevent/gevent
    https://github.com/saghul/pyuv
    https://github.com/MagicStack/uvloop
    '''
